// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/interpreter/bytecode-register.h"

namespace v8 {
namespace internal {
    namespace interpreter {

        static const int kLastParamRegisterIndex = (InterpreterFrameConstants::kRegisterFileFromFp - InterpreterFrameConstants::kLastParamFromFp) / kSystemPointerSize;
        static const int kFunctionClosureRegisterIndex = (InterpreterFrameConstants::kRegisterFileFromFp - StandardFrameConstants::kFunctionOffset) / kSystemPointerSize;
        static const int kCurrentContextRegisterIndex = (InterpreterFrameConstants::kRegisterFileFromFp - StandardFrameConstants::kContextOffset) / kSystemPointerSize;
        static const int kBytecodeArrayRegisterIndex = (InterpreterFrameConstants::kRegisterFileFromFp - InterpreterFrameConstants::kBytecodeArrayFromFp) / kSystemPointerSize;
        static const int kBytecodeOffsetRegisterIndex = (InterpreterFrameConstants::kRegisterFileFromFp - InterpreterFrameConstants::kBytecodeOffsetFromFp) / kSystemPointerSize;
        static const int kCallerPCOffsetRegisterIndex = (InterpreterFrameConstants::kRegisterFileFromFp - InterpreterFrameConstants::kCallerPCOffsetFromFp) / kSystemPointerSize;

        Register Register::FromParameterIndex(int index, int parameter_count)
        {
            DCHECK_GE(index, 0);
            DCHECK_LT(index, parameter_count);
            int register_index = kLastParamRegisterIndex - parameter_count + index + 1;
            DCHECK_LT(register_index, 0);
            return Register(register_index);
        }

        int Register::ToParameterIndex(int parameter_count) const
        {
            DCHECK(is_parameter());
            return index() - kLastParamRegisterIndex + parameter_count - 1;
        }

        Register Register::function_closure()
        {
            return Register(kFunctionClosureRegisterIndex);
        }

        bool Register::is_function_closure() const
        {
            return index() == kFunctionClosureRegisterIndex;
        }

        Register Register::current_context()
        {
            return Register(kCurrentContextRegisterIndex);
        }

        bool Register::is_current_context() const
        {
            return index() == kCurrentContextRegisterIndex;
        }

        Register Register::bytecode_array()
        {
            return Register(kBytecodeArrayRegisterIndex);
        }

        bool Register::is_bytecode_array() const
        {
            return index() == kBytecodeArrayRegisterIndex;
        }

        Register Register::bytecode_offset()
        {
            return Register(kBytecodeOffsetRegisterIndex);
        }

        bool Register::is_bytecode_offset() const
        {
            return index() == kBytecodeOffsetRegisterIndex;
        }

        // static
        Register Register::virtual_accumulator()
        {
            return Register(kCallerPCOffsetRegisterIndex);
        }

        OperandSize Register::SizeOfOperand() const
        {
            int32_t operand = ToOperand();
            if (operand >= kMinInt8 && operand <= kMaxInt8) {
                return OperandSize::kByte;
            } else if (operand >= kMinInt16 && operand <= kMaxInt16) {
                return OperandSize::kShort;
            } else {
                return OperandSize::kQuad;
            }
        }

        bool Register::AreContiguous(Register reg1, Register reg2, Register reg3,
            Register reg4, Register reg5)
        {
            if (reg1.index() + 1 != reg2.index()) {
                return false;
            }
            if (reg3.is_valid() && reg2.index() + 1 != reg3.index()) {
                return false;
            }
            if (reg4.is_valid() && reg3.index() + 1 != reg4.index()) {
                return false;
            }
            if (reg5.is_valid() && reg4.index() + 1 != reg5.index()) {
                return false;
            }
            return true;
        }

        std::string Register::ToString(int parameter_count) const
        {
            if (is_current_context()) {
                return std::string("<context>");
            } else if (is_function_closure()) {
                return std::string("<closure>");
            } else if (is_parameter()) {
                int parameter_index = ToParameterIndex(parameter_count);
                if (parameter_index == 0) {
                    return std::string("<this>");
                } else {
                    std::ostringstream s;
                    s << "a" << parameter_index - 1;
                    return s.str();
                }
            } else {
                std::ostringstream s;
                s << "r" << index();
                return s.str();
            }
        }

    } // namespace interpreter
} // namespace internal
} // namespace v8
